var FilterRunner = function(filter, safeDoc) {
	var logger = new Logger("FilterRunner");
	this.run = function() {
		logger.debug("typeof filter.filter is " + (typeof filter.filter));
		var safeWin = safeDoc.defaultView;
		var unsafeWin = safeWin.wrappedJSObject;
		var myurls = injectScripts(filter, safeDoc.location.href, unsafeWin);
		logger.debug("length resultArray is " + myurls.length);
		if (logger.logLevel < 1) {
			var result = "resultArray: ";
			for (var i = 0; i < myurls.length; i++) {
				result += "{ src: '" + myurls[i].src + "', ";
				result += " desc: '" + myurls[i].desc + "', ";
				result += " thumb: '" + myurls[i].thumb + "', ";
				result += " link: '" + myurls[i].link + "' }";
				result += ", ";
			}
			logger.debug(result);
		}
		return myurls;
	}
	// injectScripts and evalInSandbox code is copied from greasemonkey.js
	// we should running filter in sandbox environment for security reason.
	var injectScripts = function(filter, url, unsafeContentWin) {
		var sandbox;
		// force log
		var logger = new Logger(filter.id, -999);
		var safeWin = new XPCNativeWrapper(unsafeContentWin);
		var safeDoc = safeWin.document;

		sandbox = new Components.utils.Sandbox(safeWin);

		sandbox.window = safeWin;
		sandbox.document = sandbox.window.document;
		sandbox.unsafeWindow = unsafeContentWin;
		sandbox.resultURLArray = null;

		// hack XPathResult since that is so commonly used
		sandbox.XPathResult = Components.interfaces.nsIDOMXPathResult;

		sandbox.logger = logger;

		sandbox.__proto__ = safeWin;

		evalInSandbox("resultURLArray = (" + filter.filter + ")()", url,
				sandbox, filter);
		var tmpArray = new Array();
		// return new Array instance
		return tmpArray.concat(sandbox.resultURLArray);
	}
	var evalInSandbox = function(code, codebase, sandbox, script) {
		if (!(Components.utils && Components.utils.Sandbox)) {
			var e = new Error("Could not create sandbox.");
			logger.error("error creating sandbox", e);
		} else {
			try {
				// workaround for
				// https://bugzilla.mozilla.org/show_bug.cgi?id=307984
				var lineFinder = new Error();
				Components.utils.evalInSandbox(code, sandbox);
			} catch (e) {
				// try to find the line of the actual error line
				var line = e.lineNumber;
				if (4294967295 == line) {
					// Line number is reported as max int in edge cases.
					// Sometimes the right one is in the "location", instead.
					// Look there.
					if (e.location && e.location.lineNumber) {
						line = e.location.lineNumber;
					} else {
						// Reporting max int is useless, if we couldn't find it
						// in location either, forget it. Value of 0 isn't shown
						// in the console.
						line = 0;
					}
				}

				if (line) {
					line = line - lineFinder.lineNumber - 1;
				}
				e.lineNumber = line;
				logger.error("error running filter: " + filter.id
						+ ", error at line " + line, e);
			}
		}
	}
}